home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 526-550 / disk_540 / browser / browserii_src.lzh / Actions.c < prev    next >
C/C++ Source or Header  |  1991-07-29  |  18KB  |  673 lines

  1. /*
  2.  *    Actions.c - Copyright © 1991 by S.R. & P.C.
  3.  *
  4.  *    Created:    02 Mar 1991  15:50:36
  5.  *    Modified:    29 Jul 1991  07:10:23
  6.  *
  7.  *    Make>> make
  8.  */
  9.  
  10. #include "Global.h"
  11. #include "DosVar.h"
  12. #include "FileList.h"
  13. #include "ActionBack.h"
  14. #include "Process.h"
  15. #include "proto/Actions.h"
  16. #include "proto/Copy.h"
  17. #include "proto/ActionBack.h"
  18. #include "proto/Request.h"
  19. #include "proto/File.h"
  20. #include "proto/FileList.h"
  21.  
  22.  
  23. extern void setmem(void *mem, size_t size, long value);
  24.  
  25. extern struct ExecBase *SysBase;
  26. extern char *ReqTitle;
  27.  
  28.  
  29. /* just request cmd can't be done on volumes/devices/assigns */
  30.  
  31. static void TellNoVolumes(char *cmd)
  32. {
  33.     SimpleRequest(ReqTitle, "Can't %s volumes.", cmd);
  34. }
  35.  
  36.  
  37. /* Get the only element of list */
  38.  
  39. static struct SuperFileInfo *GetSelected(struct HeadFileList *hfl)
  40. {
  41.     struct BrowserDir *bd;
  42.  
  43.     bd = (struct BrowserDir *)hfl->DirList.mlh_Head;
  44.     return (struct SuperFileInfo *)bd->SuperFileList.mlh_Head;
  45. }
  46.  
  47.  
  48. /* Tell if str has a single star in it. if yes, return a pointer to it */
  49.  
  50. static char *has_star(char *str)
  51. {
  52.     char *s;
  53.  
  54.     while(*str && *str != '*') str++;
  55.     if (!*str)
  56.         return NULL;    /* no '*' in str */
  57.     else
  58.         s = str++;        /* '*' found so keep pointer and skip it */
  59.     while(*str && *str != '*') str++;
  60.     /* now, if *str != '\0', another star was found, so return NULL */
  61.     return (*str) ? NULL : s;
  62. }
  63.  
  64.  
  65. /*
  66.  *    Check for difference between the two names to make sure rename/duplicate
  67.  *    can be done. The new name mustn't be a single star, that is to say "*".
  68.  *    If the old one have a star '*' in it, the new one MUST have one too and
  69.  *    only one. And if the old name has no star, the two names must be different.
  70.  *    If ok, then preparse new name as a format for SPrintf(). 
  71.  */
  72.  
  73. static BOOL ValidRenDup(char *NewName, char *OldName)
  74. {
  75.     char buf[32];
  76.     char *s;
  77.  
  78.     if (!(*NewName) || !strcmp(NewName, "*") || !strcmp(NewName, OldName))
  79.         return FALSE;
  80.     if (has_star(OldName)) {
  81.         if (!(s = has_star(NewName))) {
  82.             SimpleRequest(ReqTitle, "You MUST keep a single '*' in name.");
  83.             return FALSE;
  84.         }
  85.         else {
  86.             strcpy(buf, s+1);    /* save prefix in buf */
  87.             strcpy(s, "%s");    /* replace '*' with "%s" */
  88.             strcpy(s+2, buf);    /* restore prefix */
  89.         }
  90.     }
  91.     return TRUE;
  92. }
  93.  
  94.  
  95. /* Build new name with name and pattern given by Init rename/duplicate */
  96.  
  97. short MakeNewName(char *NewName, char *fmt, char *OldName)
  98. {
  99.     char buffer[64];
  100.  
  101.     if (SPrintf(buffer, fmt, OldName) > 30) {
  102.         /* multiply result by 2 because "Skip" take place of usual "Retry" in
  103.          * requester and no retry is provided here. */
  104.         return ThreeGadRequest("Skip", NULL, "Filename to long: \"%s\"", buffer) << 1;
  105.     }
  106.     else {
  107.         /* give back newname only if no trouble */
  108.         strcpy(NewName, buffer);
  109.         return A_RETRY;
  110.     }
  111. }
  112.  
  113.  
  114. static BOOL InitRename(struct HeadFileList *hfl)
  115. {
  116.     struct SuperFileInfo *sfi;
  117.     BPTR VolumeLock;
  118.     char *Title, *NewName, *s;
  119.     char tmpbuf[32];
  120.     short Ok = A_RETRY;
  121.  
  122.     if (hfl->Vols > 1 || hfl->Vols && hfl->Vols < hfl->NumEntries) {
  123.         SimpleRequest(ReqTitle, "Can't relabel multiple volumes.");
  124.         return FALSE;
  125.     }
  126.     if (hfl->NumEntries > 1 || (hfl->Select.si_Flags & SI_AFFECT_SUBDIRS)) {
  127.         strcpy(tmpbuf, "*");
  128.         Title = "Add suffix and/or prefix...";
  129.     }
  130.     else if (hfl->NumEntries == 1) {
  131.         Title = "Enter new name...";
  132.         sfi = GetSelected(hfl);
  133.         strcpy(tmpbuf, sfi->FileInfo.fi_Name);
  134.         switch(sfi->FileInfo.fi_Type) {
  135.         case DLX_ASSIGN:
  136.             SimpleRequest(ReqTitle, "Can't rename an assign.");
  137.             return FALSE;
  138.         case DLX_DEVICE:    /* for a device, obtain mounted volume name, and continue to volume handling routine */
  139.             while(Ok == A_RETRY && !(VolumeLock = Lock(tmpbuf, ACCESS_READ)))
  140.                 Ok = ThreeGadRequest("Retry", NULL, "Couldn't access \"%s\"\n%s.", tmpbuf, StrIoErr());
  141.             if (Ok != A_RETRY)
  142.                 return FALSE;
  143.             PathName(VolumeLock, tmpbuf, 31);
  144.             UnLock(VolumeLock);
  145.         case DLX_VOLUME:    /* for a volume, remove ending ':' */
  146.         case DLX_UNMOUNTED:
  147.             s = &tmpbuf[strlen(tmpbuf)-1];
  148.             if (*s == ':') *s = '\0';
  149.             break;
  150.         }
  151.     }
  152.     else
  153.         return FALSE;
  154.     NewName = hfl->ActionArgs.NewName;
  155.     strcpy(NewName, tmpbuf);
  156.     if (GetString(NewName, Title, NULL, 38, 31) && ValidRenDup(NewName, tmpbuf))
  157.         return TRUE;
  158.     else
  159.         return FALSE;
  160. }
  161.  
  162.  
  163. static BOOL InitTouch(struct HeadFileList *hfl)
  164. {
  165.     if (hfl->Vols) {
  166.         TellNoVolumes("touch");
  167.         return FALSE;
  168.     }
  169.     DateStamp(&hfl->ActionArgs.DateStamp);
  170.     return TRUE;
  171. }
  172.  
  173.  
  174. static BOOL InitSetComment(struct HeadFileList *hfl)
  175. {
  176.     char buf[82];
  177.     char *s;
  178.  
  179.     if (hfl->Vols) {
  180.         TellNoVolumes("comment");
  181.         return FALSE;
  182.     }
  183.     if (hfl->NumEntries == 0)
  184.         return FALSE;
  185.     buf[0] = '\0';
  186.     if (hfl->NumEntries == 1 && (s = GetSelected(hfl)->FileInfo.fi_Comment))
  187.         strcpy(buf, s);
  188.     if (GetString(buf, "Set Comment...", NULL, 50, 80)) {
  189.         strcpy(hfl->ActionArgs.Comment, buf);
  190.         return TRUE;
  191.     }
  192.     return FALSE;
  193. }
  194.  
  195.  
  196. static BOOL InitSetProtect(struct HeadFileList *hfl)
  197. {
  198.     struct SelectInfo SelectInfo;
  199.  
  200.     if (hfl->Vols) {
  201.         TellNoVolumes("protect");
  202.         return FALSE;
  203.     }
  204.     if (hfl->NumEntries == 0)
  205.         return FALSE;
  206.     else if (hfl->NumEntries == 1 && !(hfl->Select.si_Flags & SI_AFFECT_SUBDIRS))
  207.         SelectInfo.si_PosProtect = GetSelected(hfl)->FileInfo.fi_Protection;
  208.     else
  209.         SelectInfo.si_PosProtect = 0x0F;    /* four lower bits (rwed) */
  210.     SelectInfo.si_NegProtect = 0;
  211.     if (FiltersReq(&SelectInfo, PROTECT_REQ)) {
  212.         hfl->ActionArgs.Protection.Pos = SelectInfo.si_PosProtect;
  213.         hfl->ActionArgs.Protection.Neg = SelectInfo.si_NegProtect;
  214.         return TRUE;
  215.     }
  216.     return FALSE;
  217. }
  218.  
  219.  
  220. static BOOL InitDelete(struct HeadFileList *hfl)
  221. {
  222.     char *MiddleText = NULL;
  223.     short Flags;
  224.  
  225.     if (hfl->Vols) {
  226.         TellNoVolumes("delete");
  227.         return FALSE;
  228.     }
  229.     if (hfl->NumEntries == 0)
  230.         return FALSE;
  231.     Flags = hfl->Select.si_Flags;
  232.     /* Don't ask for Delete All if AFFECT_SUBDIRS and DIRS isn't selected */
  233.     if (hfl->Dirs)
  234.         MiddleText = "Delete All";
  235.     switch(ThreeGadRequest("Delete", MiddleText, "Really delete all marked files ?")) {
  236.     case 0:        /* CANCEL */
  237.         return FALSE;
  238.     case 1:        /* DELETE */
  239.         /* Delete files and non-empty dirs */
  240.         break;
  241.     case 2:        /* DELETE ALL */
  242.         if (!(hfl->Select.si_Flags & SI_AFFECT_SUBDIRS))
  243.             hfl->Select.si_Flags = SI_AFFECT_SUBDIRS|SI_ALL_FILES|SI_ALL_DIRS;
  244.     }
  245.     return TRUE;
  246. }
  247.  
  248.  
  249. static BOOL InitAndDoDuplicate(struct HeadFileList *hfl)
  250. {
  251.     char tmpbuf[40];
  252.     char *Title, *NewName;
  253.  
  254.     NewName = hfl->ActionArgs.NewName;
  255.     if (hfl->Vols) {
  256.         TellNoVolumes("duplicate");
  257.         return FALSE;
  258.     }
  259.     if (hfl->NumEntries > 1 || (hfl->Select.si_Flags & SI_AFFECT_SUBDIRS)) {
  260.         strcpy(tmpbuf, "*");
  261.         Title = "Add suffix and/or prefix...";
  262.     }
  263.     else if (hfl->NumEntries == 1) {
  264.         strcpy(tmpbuf, GetSelected(hfl)->FileInfo.fi_Name);
  265.         Title = "Duplicate...";
  266.     }
  267.     else
  268.         return FALSE;
  269.     strcpy(NewName, tmpbuf);
  270.     if (GetString(NewName, Title, NULL, 38, 31) && ValidRenDup(NewName, tmpbuf)) {
  271.         if (BaseName(NewName) == NewName) {
  272.             hfl->CopyMode = (hfl->CopyMode & ~(CM_ALLWAYS_MOVE|CM_CONTEXT)) | CM_ALLWAYS_COPY;    /* Tell CopyMove() to copy ! */
  273.             CopyMove(hfl);
  274.         }
  275.         else
  276.             SimpleRequest(ReqTitle, "Full path name not allowed for Duplicate.");
  277.     }
  278.     return FALSE;    /* Allways return FALSE since the action is done in InitAction */
  279. }
  280.  
  281.  
  282. static short MakeDir(struct HeadFileList *hfl, char *Name)
  283. {
  284.     struct SuperFileInfo sfi;
  285.     struct FileInfoBlock *fib;
  286.     BPTR NewDir;
  287.     short Ok = A_RETRY;
  288.  
  289.     if (!(fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR)))
  290.         return FALSE;
  291.     setmem(&sfi, sizeof(struct SuperFileInfo), 0);
  292.     /* Prevent CreateDir() bug which create a dir even if a file with the same name already exists */
  293.     while(Ok == A_RETRY && (NewDir = Lock(Name, ACCESS_READ))) {
  294.         UnLock(NewDir);
  295.         Ok = ThreeGadRequest("Retry", "Skip", "Couldn't create dir \"%s\"\n%s.", Name, "Object already exists");
  296.     }
  297.     while(Ok == A_RETRY && !(NewDir = CreateDir(Name)))
  298.         Ok = ThreeGadRequest("Retry", "Skip", "Couldn't create dir \"%s\"\n%s.", Name, StrIoErr());
  299.     if (Ok == A_RETRY) {
  300.         UnLock(NewDir);
  301.         if (Name == BaseName(Name) && (Ok = GetFib(Name, fib, TRUE)) == A_RETRY) {
  302.             Fib2Fi(&sfi.FileInfo, fib);
  303.             strcpy(sfi.OldName, sfi.FileInfo.fi_Name);
  304.             sfi.ActionBack |= AB_NEW_ENTRY;
  305.             SendActionBack(&sfi, NULL, hfl->DestDir);
  306.         }
  307.     }
  308.     FreeMem(fib, sizeof(struct FileInfoBlock));
  309.     return Ok;
  310. }
  311.  
  312.  
  313. #define MAKEDIR_BUFSIZE  46
  314.  
  315. static BOOL InitAndDoMakeDir(struct HeadFileList *hfl)
  316. {
  317.     BPTR CD;
  318.     char *s, *dir, c;
  319.     char Buffer[MAKEDIR_BUFSIZE];
  320.     BOOL quote;
  321.     short Ok = A_RETRY;
  322.  
  323.     if (!hfl->DestDir) {    /* this is the main window */
  324.         SimpleRequest(ReqTitle, "Can't create a dir in this window.");
  325.         return FALSE;
  326.     }
  327.     setmem(Buffer,  MAKEDIR_BUFSIZE, 0);
  328.     if (GetString(Buffer, "Makedir(s)...", NULL, MAKEDIR_BUFSIZE-1, MAKEDIR_BUFSIZE-1)) {
  329.         CD = CurrentDir(hfl->DestDir);
  330.         s = Buffer;
  331.         while (Ok != A_STOP && *s) {
  332.             while ((c = *s) && (c == ' ' || c == '\t'))
  333.                 s++;        /* skip leading spaces */
  334.             if (!c)
  335.                 break;
  336.             if (c == '"') {
  337.                 quote = TRUE;
  338.                 s++;
  339.             }
  340.             else
  341.                 quote = FALSE;
  342.             dir = s;
  343.             while((c = *s) && ((quote && c != '"') || (!quote && c != ' ')))
  344.                 s++;
  345.             *s++ = '\0';
  346.             Ok = MakeDir(hfl, dir);
  347.         }
  348.         SendUpdateDir(hfl->DestDir);
  349.         CurrentDir(CD);
  350.     }
  351.     return FALSE;    /* Allways return FALSE since action is done in init */
  352. }
  353.  
  354.  
  355. static short DoRelabel(char *Dev, char *Name)
  356. {
  357.     long args[7];
  358.     char *str;
  359.     struct MsgPort *task;
  360.     short Ok = A_RETRY;
  361.  
  362.     while(Ok == A_RETRY && !(task = (struct MsgPort *)DeviceProc(Dev)))
  363.         Ok = ThreeGadRequest("Retry", NULL, "Couldn't access \"%s\"\n%s.", Dev, StrIoErr());
  364.     if (Ok == A_RETRY) {
  365.         str = AllocMem(65L, MEMF_PUBLIC);
  366.         CtoBStr(Name, (ULONG)str>>2, 64);
  367.         args[0] = (ULONG)str>>2;
  368.         while (Ok == A_RETRY && !SendPacket(ACTION_RENAME_DISK, args, task))
  369.             Ok = ThreeGadRequest("Retry", NULL, "Couldn't relabel \"%s\"\n%s.", Name, StrIoErr());
  370.         FreeMem(str, 65L);
  371.         if (Ok == A_RETRY) {
  372.             args[0] = 1;
  373.             SendPacket(ACTION_INHIBIT, args, task);
  374.             args[0] = 0;
  375.             SendPacket(ACTION_INHIBIT, args, task);
  376.         }
  377.     }
  378.     return Ok;
  379. }
  380.  
  381.  
  382. static short DoRename(struct SuperFileInfo *sfi, union ActionArgs *Args)
  383. {
  384.     short Ok = A_RETRY;
  385.     char *OldName, *NewName;
  386.  
  387.     OldName = sfi->OldName;
  388.     NewName = sfi->FileInfo.fi_Name;
  389.     switch(sfi->FileInfo.fi_Type) {
  390.     case DLX_DIR:
  391.     case DLX_FILE:
  392.         if ((Ok = MakeNewName(NewName, Args->NewName, OldName)) == A_RETRY) {
  393.             while(Ok == A_RETRY && !Rename(OldName, NewName))
  394.                 Ok = ThreeGadRequest("Retry", "Skip", "Couldn't rename \"%s\" as \"%s\"\n%s.", OldName, NewName, StrIoErr());
  395.             if (Ok == A_RETRY) {
  396.                 /* if newname hasn't the same directory path, just remove old file from window, else, update string */
  397.                 if (NewName == BaseName(NewName))
  398.                     sfi->ActionBack |= AB_RENAME_ENTRY;
  399.                 else
  400.                     sfi->ActionBack |= AB_DELETE_SOURCE;
  401.             }
  402.         }
  403.         break;
  404.     case DLX_DEVICE:
  405.     case DLX_VOLUME:
  406.         if ((Ok = DoRelabel(OldName, Args->NewName)) == A_RETRY)
  407.             sfi->ActionBack |= AB_SCANDEVS;
  408.         break;
  409.     }
  410.     return Ok;
  411. }
  412.  
  413.  
  414. short Touch(char *Name, struct DateStamp *ds)
  415. {
  416.     struct MsgPort *task;
  417.     long args[7];
  418.     char *str;
  419.     struct Process *pp;
  420.     short Ok = A_RETRY;
  421.  
  422.     pp = (struct Process *)SysBase->ThisTask;
  423.     while(Ok == A_RETRY && !(task = (struct MsgPort *)DeviceProc(Name)))
  424.         Ok = ThreeGadRequest("Retry", "Skip", "Couldn't access \"%s\"\n%s.", Name, StrIoErr());
  425.     if (Ok == A_RETRY) {
  426.         str = AllocMem(65, MEMF_PUBLIC);
  427.         CtoBStr(Name, (BSTR)str>>2L, 64);
  428.         args[1] = pp->pr_CurrentDir;
  429.         args[2] = (BSTR)str>>2L;
  430.         args[3] = (long)ds;
  431.         while (Ok == A_RETRY && !SendPacket(ACTION_SET_DATE, args, task))
  432.             Ok = ThreeGadRequest("Retry", "Skip", "Couldn't touch \"%s\"\n%s.", Name, StrIoErr());
  433.         FreeMem(str, 65);
  434.     }
  435.     return Ok;
  436. }
  437.  
  438.  
  439. static short DoTouch(struct SuperFileInfo *sfi, union ActionArgs *Args)
  440. {
  441.     short Ok;
  442.  
  443.     if ((Ok = Touch(sfi->FileInfo.fi_Name, &Args->DateStamp)) == A_RETRY) {
  444.         sfi->FileInfo.fi_Date = Args->DateStamp;
  445.         sfi->ActionBack |= AB_UPDATE_STRING;
  446.     }
  447.     return Ok;
  448. }
  449.  
  450.  
  451. short Comment(char *Name, char *FileNote)
  452. {
  453.     short Ok = A_RETRY;
  454.  
  455.     while (Ok == A_RETRY && !SetComment(Name, FileNote))
  456.         Ok = ThreeGadRequest("Retry", "Skip", "Couldn't set comment of \"%s\"\n%s.", Name, StrIoErr());
  457.     return Ok;
  458. }
  459.  
  460.  
  461. static short DoSetComment(struct SuperFileInfo *sfi, union ActionArgs *Args)
  462. {
  463.     short Ok = A_RETRY;
  464.  
  465.     if (Ok = Comment(sfi->FileInfo.fi_Name, Args->Comment)) {
  466.         CleanFileInfo(&sfi->FileInfo);
  467.         if (strlen(Args->Comment)) {
  468.             sfi->FileInfo.fi_Comment = CopyStr(Args->Comment);
  469.             sfi->FileInfo.fi_Protection |= FIBF_COMMENT;
  470.         }
  471.         else
  472.             sfi->FileInfo.fi_Protection &= ~FIBF_COMMENT;
  473.         sfi->ActionBack |= AB_UPDATE_STRING;
  474.     }
  475.     return Ok;
  476. }
  477.  
  478.  
  479. short Protect(char *Name, long Protection)
  480. {
  481.     short Ok = A_RETRY;
  482.  
  483.     Protection = (Protection & 0x00FF) ^ 0x0F;    /* clear comment bit and complement four lower bits. strange AmigaDOS !! */
  484.     while (Ok == A_RETRY && !SetProtection(Name, Protection))
  485.         Ok = ThreeGadRequest("Retry", "Skip", "Couldn't protect \"%s\"\n%s.", Name, StrIoErr());
  486.     return Ok;
  487. }
  488.  
  489.  
  490. static short DoSetProtect(struct SuperFileInfo *sfi, union ActionArgs *Args)
  491. {
  492.     long Protection;
  493.     short Ok = A_RETRY;
  494.  
  495.     if (Args->Protection.Neg & FIBF_COMMENT) {    /* Protect -c "file" means remove comment */
  496.         if ((Ok = Comment(sfi->FileInfo.fi_Name, "")) == A_RETRY)
  497.             CleanFileInfo(&sfi->FileInfo);
  498.     }
  499.     Protection = (sfi->FileInfo.fi_Protection | Args->Protection.Pos) & ~Args->Protection.Neg;
  500.     if (Ok == A_RETRY && (Ok = Protect(sfi->FileInfo.fi_Name, Protection))) {
  501.         sfi->FileInfo.fi_Protection = Protection;
  502.         sfi->ActionBack |= AB_UPDATE_STRING;
  503.     }
  504.     return Ok;
  505. }
  506.  
  507.  
  508. /*
  509.  *    Don't request for a directory not empty since user may already
  510.  *    has answered after a file couldn't be deleted in this dir.
  511.  */
  512.  
  513. static short DoDelete(struct SuperFileInfo *sfi)
  514. {
  515.     char *Name;
  516.     short err=0, Ok = A_RETRY;
  517.  
  518.     Name = sfi->FileInfo.fi_Name;
  519.     while (Ok == A_RETRY && !DeleteFile(Name) && (err = IoErr()) != ERROR_DIRECTORY_NOT_EMPTY) {
  520.         Ok = ThreeGadRequest("Retry", "Skip", "Couldn't delete \"%s\"\n%s.", Name, DosError(err));
  521.         err = 0;
  522.     }
  523.     if (Ok == A_RETRY && err == 0)
  524.         sfi->ActionBack |= AB_DELETE_SOURCE;
  525.     return Ok;
  526. }
  527.  
  528.  
  529. static short DoRecurse(struct HeadFileList *hfl, struct SuperFileInfo *StartSFI, struct FileInfoBlock *StartFib, short (*Action)(struct SuperFileInfo *, union ActionArgs *))
  530. {
  531.     struct SuperFileInfo *sfi;
  532.     struct FileInfoBlock *OldFib, *fib;
  533.     struct SelectInfo *Select;
  534.     char *DirName;
  535.     BPTR DirLock, CD;
  536.     short err = 0, Ok = A_RETRY;
  537.     long next;
  538.  
  539.     fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR);
  540.     OldFib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR);
  541.     sfi = AllocMem(sizeof(struct SuperFileInfo), MEMF_PUBLIC|MEMF_CLEAR);
  542.     if (fib && OldFib && sfi) {
  543.         Select = &hfl->Select;
  544.         DirName = StartFib->fib_FileName;
  545.         while(Ok == A_RETRY && !(DirLock = Lock(DirName, ACCESS_READ)))
  546.             Ok = ThreeGadRequest("Retry", "Skip", "Couldn't access \"%s\"\n%s.", DirName, StrIoErr());
  547.         if (Ok == A_RETRY && DirLock) {
  548.             CD = CurrentDir(DirLock);
  549.             *fib = *StartFib;
  550.             if (!(next = ExNext(DirLock, fib)) && (err = IoErr()) != ERROR_NO_MORE_ENTRIES)
  551.                 Ok = ThreeGadRequest("Skip", NULL, "Error reading directory \"%s\"\n%s.", DirName, DosError(err)) << 1;
  552.             if (Ok == A_RETRY) {
  553.                 while(Ok != A_STOP && next) {
  554.                     *OldFib = *fib;
  555.                     Fib2Fi(&sfi->FileInfo, fib);
  556.                     /* Examine next entry before possible delete (need for Commodore RAM disk) */
  557.                     next = ExNext(DirLock, fib);
  558.                     err = IoErr();
  559.                     strcpy(sfi->OldName, sfi->FileInfo.fi_Name);    /* save name for actions which change it */
  560.                     switch(sfi->FileInfo.fi_Type) {
  561.                     case DLX_FILE:
  562.                         if (MatchFilters(&sfi->FileInfo, Select))
  563.                             Ok = Action(sfi, &hfl->ActionArgs);
  564.                         break;
  565.                     case DLX_DIR:
  566.                         Ok = DoRecurse(hfl, sfi, OldFib, Action);
  567.                     }
  568.                     if (Ok != A_RETRY)
  569.                         sfi->ActionBack = AB_SELECT;
  570.                     SendActionBack(sfi, DirLock, NULL);
  571.                 }
  572.                 if (Ok == A_RETRY && err != ERROR_NO_MORE_ENTRIES)
  573.                     Ok = ThreeGadRequest("Skip", NULL, "Error reading directory \"%s\"\n%s.", DirName, DosError(err)) << 1;
  574.                 CleanFileInfo(&sfi->FileInfo);
  575.             }
  576.             CurrentDir(CD);
  577.             SendUpdateDir(DirLock);
  578.             UnLock(DirLock);
  579.         }
  580.         if (Ok == A_RETRY && MatchFilters(&StartSFI->FileInfo, Select))
  581.             Ok = Action(StartSFI, &hfl->ActionArgs);
  582.     }
  583.     else
  584.         Ok = A_STOP;
  585.     if (sfi) FreeMem(sfi, sizeof(struct SuperFileInfo));
  586.     if (OldFib) FreeMem(OldFib, sizeof(struct FileInfoBlock));
  587.     if (fib) FreeMem(fib, sizeof(struct FileInfoBlock));
  588.     return Ok;
  589. }
  590.  
  591.  
  592. static BOOL (*InitActionArray[])(struct HeadFileList *) = {
  593.     InitRename,
  594.     InitAndDoMakeDir,
  595.     InitAndDoDuplicate,
  596.     InitTouch,
  597.     InitSetComment,
  598.     InitSetProtect,
  599.     InitDelete
  600. };
  601.  
  602.  
  603. static BOOL (*DoActionArray[])() = {
  604.     DoRename,
  605.     NULL,
  606.     NULL,
  607.     DoTouch,
  608.     DoSetComment,
  609.     DoSetProtect,
  610.     DoDelete
  611. };
  612.  
  613.  
  614. void DoAction(struct HeadFileList *hfl, short ActionNum)
  615. {
  616.     struct BrowserDir *bd;
  617.     struct SuperFileInfo *sfi;
  618.     struct FileInfoBlock *fib;
  619.     short (*Action)(struct SuperFileInfo *, union ActionArgs *);
  620.     short Ok = A_RETRY;
  621.  
  622.     if (!(fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR)))
  623.         return;
  624.     Action = DoActionArray[ActionNum];
  625.     bd = (struct BrowserDir *)hfl->DirList.mlh_Head;
  626.     while( Ok != A_STOP && bd->Node.mln_Succ ) {
  627.         if (bd->DirLock)
  628.             CurrentDir(bd->DirLock);
  629.         sfi = (struct SuperFileInfo *)bd->SuperFileList.mlh_Head;
  630.         while(Ok != A_STOP && sfi->Node.mln_Succ) {
  631.             /* Examine entry only if necessary */
  632.             if (sfi->FileInfo.fi_Type == DLX_DIR && (hfl->Select.si_Flags & SI_AFFECT_SUBDIRS)) {
  633.                 if ((Ok = GetFib(sfi->FileInfo.fi_Name, fib, TRUE)) == A_RETRY)
  634.                     Fib2Fi(&sfi->FileInfo, fib);
  635.             }
  636.             else
  637.                 Ok = A_RETRY;
  638.             if (Ok == A_RETRY) {
  639.                 switch(sfi->FileInfo.fi_Type) {
  640.                 case DLX_FILE:
  641.                     Ok = Action(sfi, &hfl->ActionArgs);
  642.                     break;
  643.                 case DLX_DIR:
  644.                     if (hfl->Select.si_Flags & SI_AFFECT_SUBDIRS)
  645.                         Ok = DoRecurse(hfl, sfi, fib, Action);
  646.                     else
  647.                         Ok = Action(sfi, &hfl->ActionArgs);
  648.                     break;
  649.                 default:    /* Assign, Device, or Volume */
  650.                     Ok = Action(sfi, &hfl->ActionArgs);
  651.                 }
  652.             }
  653.             if (Ok != A_RETRY)
  654.                 sfi->ActionBack = AB_SELECT;
  655.             SendActionBack(sfi, bd->DirLock, NULL);
  656.             sfi = (struct SuperFileInfo *)sfi->Node.mln_Succ;
  657.         }
  658.         SendUpdateDir(bd->DirLock);
  659.         bd = (struct BrowserDir *)bd->Node.mln_Succ;
  660.     }
  661.     CurrentDir(((struct TaskData *)SysBase->ThisTask->tc_UserData)->td_InitialDir);
  662.     FreeMem(fib, sizeof(struct FileInfoBlock));
  663. }
  664.  
  665.  
  666. void InitAndDoAction(struct HeadFileList *hfl, short ActionNum)
  667. {
  668.     if (InitActionArray[ActionNum](hfl))
  669.         DoAction(hfl, ActionNum);
  670. }
  671.  
  672.  
  673.